/********************************************************/
/*	Copyright (C) 2016 Gong Li Bin			*/
/*	Project:	GlbCloud			*/
/*	Author:		gong_libin			*/
/*	Date:		2012_01_09			*/
/*	File:		MrTcp.cpp			*/
/********************************************************/

#include "MrTcp.h"

CMrTcp::CMrTcp()
{
	m_pFunction = NULL;
}

CMrTcp::~CMrTcp()
{
	m_pFunction = NULL;
}

void CMrTcp::MrTcpAccept()
{
	int iNewSocket = 0;
	socklen_t iClientSize = 0;
	struct sockaddr_in stClient;

	iClientSize = (socklen_t)sizeof(struct sockaddr_in);
	while (1) {
		iNewSocket = accept(CMrNet::m_iSocket, (struct sockaddr*)&stClient, &iClientSize);
		if (iNewSocket > 0) {
			(*m_pFunction)(iNewSocket);
		}
	}

	return;
}

void CMrTcp::MrTcpSetFunction(void (*pFunction)(int))
{
	m_pFunction = pFunction;

	return;
}

int CMrTcp::MrTcpSetNoDelay()
{
	int iOn = 1;

	if (MR_FAILURE == setsockopt(CMrNet::m_iSocket, IPPROTO_TCP, TCP_NODELAY, &iOn, sizeof(iOn))) {
		MR_ERROR("%s\n", strerror(errno));
		return MR_FAILURE;
	}

	return MR_SUCCESS;
}

void CMrTcp::MrTcpShutdown(int iHow)
{
	shutdown(CMrNet::m_iSocket, iHow);

	return;
}

int CMrTcp::MrTcpSetLinger(int iSecond)
{
	struct linger stLinger;

	stLinger.l_onoff = 1;
	stLinger.l_linger = iSecond;

	if (MR_FAILURE == setsockopt(CMrNet::m_iSocket, SOL_SOCKET, SO_LINGER, (char*)&stLinger, sizeof(struct linger))) {
		MR_ERROR("%s\n", strerror(errno));
		return MR_FAILURE;
	}

	return MR_SUCCESS;
}

int CMrTcp::MrTcpInit(char* pszPort)
{
	struct sockaddr_in stServer;

	memset(&stServer, '\0', sizeof(struct sockaddr_in));
	stServer.sin_addr.s_addr = htonl(INADDR_ANY);
	stServer.sin_port = htons(atoi(pszPort));
	stServer.sin_family = AF_INET;

	if (MR_SUCCESS != CMrNet::MrNetOpen(MR_SOCK_STREAM)) {
		return MR_FAILURE;
	}

	if (bind(CMrNet::m_iSocket, (struct sockaddr*)&stServer, sizeof(struct sockaddr_in)) < 0) {
		MR_ERROR("%s\n", strerror(errno));
		CMrNet::MrNetClose();
		return MR_FAILURE;
	}

	if (listen(CMrNet::m_iSocket, MR_LISTEN) < 0) {
		MR_ERROR("%s\n", strerror(errno));
		CMrNet::MrNetClose();
		return MR_FAILURE;
	}

	return MR_SUCCESS;
}

int CMrTcp::MrTcpConnect(char* pszUrl)
{
	char* pszPort = NULL;
	int iReturn = MR_SUCCESS;

	if (NULL != (pszPort = CMrNet::MrNetUrl(pszUrl))) {
		iReturn = MrTcpConnect(pszUrl, pszPort);
	}
	else {
		iReturn = MR_FAILURE;
	}

	return iReturn;
}

int CMrTcp::MrTcpConnect(struct sockaddr_in* pstAddr)
{
	int iReturn = MR_SUCCESS;

	if (MR_SUCCESS == CMrNet::MrNetOpen(MR_SOCK_STREAM)) {
		CMrNet::MrNetSetTimeOut(MR_TIMEOUT, 0);
		if (connect(CMrNet::m_iSocket, (struct sockaddr*)pstAddr, sizeof(struct sockaddr_in)) < 0) {
			MR_ERROR("%s\n", strerror(errno));
			iReturn = MR_FAILURE;
			CMrNet::MrNetClose();
		}
	}
	else {
		iReturn = MR_FAILURE;
	}

	return iReturn;
}

int CMrTcp::MrTcpConnect(char* pszAddress, char* pszPort)
{
	int iReturn = MR_SUCCESS;
	struct sockaddr_in stAddr;

	memset(&stAddr, '\0', sizeof(struct sockaddr_in));
	stAddr.sin_addr.s_addr = inet_addr(pszAddress);
	stAddr.sin_port = htons(atoi(pszPort));
	stAddr.sin_family = AF_INET;

	if (MR_SUCCESS == CMrNet::MrNetOpen(MR_SOCK_STREAM)) {
		CMrNet::MrNetSetTimeOut(MR_TIMEOUT, 0);
		if (connect(CMrNet::m_iSocket, (struct sockaddr*)&stAddr, sizeof(struct sockaddr_in)) < 0) {
			MR_ERROR("%s\n", strerror(errno));
			iReturn = MR_FAILURE;
			CMrNet::MrNetClose();
		}
	}
	else {
		iReturn = MR_FAILURE;
	}

	return iReturn;
}

int CMrTcp::MrNetSend(UCHAR* puszPacket, int iLength)
{
	return send(CMrNet::m_iSocket, puszPacket, iLength, 0);
}

int CMrTcp::MrNetRecv(UCHAR* puszPacket, int iLength)
{
	return recv(CMrNet::m_iSocket, puszPacket, iLength, 0);
}

int CMrTcp::MrNetSendAll(UCHAR* puszPacket, int iLength)
{
	int iCount = 0;
	int iTotal = 0;

	while (iTotal < iLength) {
		if ((iCount = MrNetSend(puszPacket + iTotal, iLength - iTotal)) > 0) {
			iTotal += iCount;
		}
		else {
			MR_ERROR("%s\n", strerror(errno));
			break;
		}
	}

	return iTotal;

}

int CMrTcp::MrNetRecvAll(UCHAR* puszPacket, int iLength)
{
	int iCount = 0;
	int iTotal = 0;

	while (iTotal < iLength) {
		if ((iCount = MrNetRecv(puszPacket + iTotal, iLength - iTotal)) > 0) {
			iTotal += iCount;
		}
		else {
			MR_ERROR("%s\n", strerror(errno));
			break;
		}
	}

	return iTotal;

}
